package service

import (
	"context"
	"fmt"
	"time"

	proto "behavior_srv/basic/behaviorproto"
	"behavior_srv/handler/dao"
	"behavior_srv/handler/models"
)

// BehaviorService 实现behavior.proto中定义的服务接口
type BehaviorService struct {
	proto.UnimplementedBehaviorServiceServer
	visitDAO *dao.VisitRecordDAO
	clickDAO *dao.ClickBehaviorDAO
	stayDAO  *dao.StayTimeDAO
}

// RecordVisit 记录用户访问
func (s *BehaviorService) RecordVisit(ctx context.Context, req *proto.RecordVisitReq) (*proto.RecordVisitResp, error) {
	// 创建访问记录模型
	visit := &models.BehaviorVisitRecords{
		UserId:       req.GetUserId(),
		UserIp:       req.GetIp(),
		SessionId:    req.GetRequestId(),
		Path:         req.GetPath(),
		PageName:     req.GetDeviceId(), // 使用DeviceID作为PageName
		VisitTime:    time.Unix(req.GetVisitTime()/1000, (req.GetVisitTime()%1000)*int64(time.Millisecond)),
		UserAgent:    req.GetUserAgent(),
		Referer:      req.GetReferer(),
		IsFirstVisit: req.GetIsFirstVisit(),
		Params:       mapToString(req.GetParams()),
		CreatedAt:    time.Now(),
		UpdatedAt:    time.Now(),
	}

	// 保存到数据库
	err := s.visitDAO.Create(visit)
	if err != nil {
		return &proto.RecordVisitResp{
			Success: false,
			Message: fmt.Sprintf("记录访问失败: %v", err),
		}, err
	}

	return &proto.RecordVisitResp{
		Success: true,
		Message: "记录访问成功",
	}, nil
}

// RecordClick 记录用户点击行为
func (s *BehaviorService) RecordClick(ctx context.Context, req *proto.RecordClickReq) (*proto.RecordClickResp, error) {
	// 创建点击行为模型
	click := &models.BehaviorClickRecords{
		UserId:       req.GetUserId(),
		SessionId:    req.GetRequestId(),
		Path:         req.GetPageUrl(),             // 使用PageURL作为Path
		PageName:     req.GetElementId(),           // 使用ElementID作为PageName
		BehaviorType: req.GetElementType(),         // 使用ElementType作为BehaviorType
		Details:      mapToString(req.GetParams()), // 使用Params作为Details
		ClickTime:    time.Unix(req.GetClickTime()/1000, (req.GetClickTime()%1000)*int64(time.Millisecond)),
		CreatedAt:    time.Now(),
		UpdatedAt:    time.Now(),
	}

	// 保存到数据库
	err := s.clickDAO.Create(click)
	if err != nil {
		return &proto.RecordClickResp{
			Success: false,
			Message: fmt.Sprintf("记录点击行为失败: %v", err),
		}, err
	}

	return &proto.RecordClickResp{
		Success: true,
		Message: "记录点击行为成功",
	}, nil
}

// RecordStayTime 记录用户停留时间
func (s *BehaviorService) RecordStayTime(ctx context.Context, req *proto.RecordStayTimeReq) (*proto.RecordStayTimeResp, error) {
	// 创建停留时间模型
	stayTime := &models.BehaviorStayTimes{
		UserId:     req.GetUserId(),
		SessionId:  req.GetRequestId(),
		Path:       req.GetPageUrl(),  // 使用PageURL作为Path
		PageName:   req.GetDeviceId(), // 使用DeviceID作为PageName
		StayTimeMs: req.GetStayDuration(),
		EnterTime:  time.Unix(req.GetStartTime()/1000, (req.GetStartTime()%1000)*int64(time.Millisecond)),
		LeaveTime:  time.Unix(req.GetEndTime()/1000, (req.GetEndTime()%1000)*int64(time.Millisecond)),
		CreatedAt:  time.Now(),
		UpdatedAt:  time.Now(),
	}

	// 保存到数据库
	err := s.stayDAO.Create(stayTime)
	if err != nil {
		return &proto.RecordStayTimeResp{
			Success: false,
			Message: fmt.Sprintf("记录停留时间失败: %v", err),
		}, err
	}

	return &proto.RecordStayTimeResp{
		Success: true,
		Message: "记录停留时间成功",
	}, nil
}

// BatchRecord 批量记录行为数据
func (s *BehaviorService) BatchRecord(ctx context.Context, req *proto.BatchRecordReq) (*proto.BatchRecordResp, error) {
	successCount := 0
	totalCount := 0

	// 处理批量访问记录
	if len(req.GetVisits()) > 0 {
		var visits []*models.BehaviorVisitRecords
		for _, v := range req.GetVisits() {
			visit := &models.BehaviorVisitRecords{
				UserId:       v.GetUserId(),
				UserIp:       v.GetIp(),
				SessionId:    v.GetRequestId(),
				Path:         v.GetPath(),
				PageName:     v.GetDeviceId(), // 使用DeviceID作为PageName
				VisitTime:    time.Unix(v.GetVisitTime()/1000, (v.GetVisitTime()%1000)*int64(time.Millisecond)),
				UserAgent:    v.GetUserAgent(),
				Referer:      v.GetReferer(),
				IsFirstVisit: v.GetIsFirstVisit(),
				Params:       mapToString(v.GetParams()),
				CreatedAt:    time.Now(),
				UpdatedAt:    time.Now(),
			}
			visits = append(visits, visit)
		}

		totalCount += len(visits)
		if err := s.visitDAO.BatchCreate(visits); err == nil {
			successCount += len(visits)
		}
	}

	// 处理批量点击记录
	if len(req.GetClicks()) > 0 {
		var clicks []*models.BehaviorClickRecords
		for _, c := range req.GetClicks() {
			click := &models.BehaviorClickRecords{
				UserId:       c.GetUserId(),
				SessionId:    c.GetRequestId(),
				Path:         c.GetPageUrl(),             // 使用PageURL作为Path
				PageName:     c.GetElementId(),           // 使用ElementID作为PageName
				BehaviorType: c.GetElementType(),         // 使用ElementType作为BehaviorType
				Details:      mapToString(c.GetParams()), // 使用Params作为Details
				ClickTime:    time.Unix(c.GetClickTime()/1000, (c.GetClickTime()%1000)*int64(time.Millisecond)),
				CreatedAt:    time.Now(),
				UpdatedAt:    time.Now(),
			}
			clicks = append(clicks, click)
		}

		totalCount += len(clicks)
		if err := s.clickDAO.BatchCreate(clicks); err == nil {
			successCount += len(clicks)
		}
	}

	// 处理批量停留时间记录
	if len(req.GetStayTimes()) > 0 {
		var stayTimes []*models.BehaviorStayTimes
		for _, st := range req.GetStayTimes() {
			stayTime := &models.BehaviorStayTimes{
				UserId:     st.GetUserId(),
				SessionId:  st.GetRequestId(),
				Path:       st.GetPageUrl(),  // 使用PageURL作为Path
				PageName:   st.GetDeviceId(), // 使用DeviceID作为PageName
				StayTimeMs: st.GetStayDuration(),
				EnterTime:  time.Unix(st.GetStartTime()/1000, (st.GetStartTime()%1000)*int64(time.Millisecond)),
				LeaveTime:  time.Unix(st.GetEndTime()/1000, (st.GetEndTime()%1000)*int64(time.Millisecond)),
				CreatedAt:  time.Now(),
				UpdatedAt:  time.Now(),
			}
			stayTimes = append(stayTimes, stayTime)
		}

		totalCount += len(stayTimes)
		if err := s.stayDAO.BatchCreate(stayTimes); err == nil {
			successCount += len(stayTimes)
		}
	}

	return &proto.BatchRecordResp{
		Success:        true,
		Message:        fmt.Sprintf("批量记录完成，成功 %d/%d", successCount, totalCount),
		TotalRecords:   int32(totalCount),
		SuccessRecords: int32(successCount),
	}, nil
}

// mapToString 将map[string]string转换为字符串存储
func mapToString(m map[string]string) string {
	if len(m) == 0 {
		return ""
	}

	result := ""
	for k, v := range m {
		if result != "" {
			result += ","
		}
		result += fmt.Sprintf("%s=%s", k, v)
	}

	return result
}
